
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>

struct fileinfo
{
    char name[50];
    uint32_t size;
};

#define BUFSIZE_MAX 10*1024

int main(int argc, char const *argv[]) // ./a.out PORT
{
    // 该套接字用来接收其他人发来的消息，必须绑定
    // 本机有效的IP/PORT，否则其他进程无法发送数据
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(atoi(argv[1]));

    // 将本机的一个可用的IP和可用的PORT
    // 跟刚创建的套接字sockfd绑定
    // 以便可以接收其他主机发来的消息
    bind(sockfd, (struct sockaddr *)&addr, len);
    listen(sockfd, 3);

    int connfd = accept(sockfd, NULL, NULL);
    if(connfd > 0)
        printf("连接成功\n");

    // 接收文件基本属性、创建文件
    struct fileinfo info;
    bzero(&info, sizeof(info));

    recv(connfd, &info, sizeof(info), 0);
    printf("即将接收: %s(%d字节)\n", info.name, info.size);

    int fd = open(info.name, O_WRONLY|O_CREAT|O_TRUNC, 0666);

    // 接收文件内容
    int bufsize = info.size > BUFSIZE_MAX ? BUFSIZE_MAX : info.size; 
    char *buf = calloc(1, bufsize);
    int total = 0;
    while(total < info.size)
    {
        bzero(buf, bufsize);
        int m = recv(connfd, buf, bufsize, 0);
        if(m == -1)
        {
            perror("recv() failed");
            break;
        }
        total += m;
        printf("已接收%d个字节\n", total);

        write(fd, buf, m);
    }

    close(fd);
    close(connfd);
    close(connfd);
    free(buf);

    return 0;
}
